import { contextMenu } from './context-menu-config';
import { cloneDeep } from 'lodash-es';
import { BsModalService } from '@farris/ui-modal';
import { ComponentFactoryResolver } from '@angular/core';
import FdContainerBaseComponent from '../../common/containerBase/containerBase';
import { RowNode } from '@farris/ui-treetable';
import { DgControl } from '../../../../utils/dg-control';
import { ContextMenuManager } from '../../../../service/context-menu.manager';
import { BindingEditorComponent } from '@farris/designer-devkit';
import { DesignViewModelField, FormBasicService, FormBinding, FormVariable } from '@farris/designer-services';
import { CreateFieldSetComponent } from './editor/create-field-set/create-field-set.component';
import { ControlContextMenuItem } from '../../../../entity/control-context-menu';

const ADD_CHILD_CONTENT_COMMAND = 'addChildContent';
const ADD_FIELDSET_COMMAND = 'addFieldSet';
/** 启用tab索引 */
const ENABLE_TAB_INDEX_MENU = 'enableTabIndex';
/** 关闭tab索引 */
const CLOSE_TAB_INDEX_MENU = 'closeTabIndex';


class ControlCreationContextByContextMenu {
  bindingValue: FormBinding;
  bindingField: DesignViewModelField | FormVariable;
  componentId: string;
  controlType: string;
  controlParentElement: any;
}

export class FormContextMenuManager extends ContextMenuManager {

  private componentFactoryResolver: ComponentFactoryResolver;
  private modalService: BsModalService;
  private controlCreatorService: any;


  constructor(cmp: FdContainerBaseComponent, rowNode: RowNode) {
    super(cmp, rowNode);

    this.componentFactoryResolver = this.serviceHost.getService('ComponentFactoryResolver');
    this.modalService = this.serviceHost.getService('ModalService');
    this.controlCreatorService = this.serviceHost.getService('ControlCreatorService');
  }
  /**
   * 过滤、修改控件树右键菜单
   */
  setContextMenuConfig() {


    let menuConfig = cloneDeep(contextMenu) as ControlContextMenuItem[];
    if (!menuConfig) {
      return [];
    }

    menuConfig = this.assembleAddChildControlMenu(this.cmpInstance.id, menuConfig, this.cmpInstance.viewModelId);
    menuConfig = this.assembleAddFieldSetMenu(this.cmpInstance.id, menuConfig, this.cmpInstance.viewModelId);

    menuConfig = this.assembleEnableTabIndexMenu(menuConfig);
    menuConfig = this.assembleCloseTabIndexMenu(menuConfig);

    // 配置菜单点击事件
    this.addContextMenuHandle(menuConfig);

    return menuConfig;
  }
  /**
   * 点击控件树右键菜单
   */
  contextMenuClicked(e: { data: RowNode, menu: ControlContextMenuItem }) {

    const menu = e.menu;

    if (menu.parentMenuId === ADD_CHILD_CONTENT_COMMAND) {
      const formElement = this.cmpInstance.component;
      this.addChildControl(menu, this.cmpInstance.componentId, formElement);
      return;
    }

    switch (menu.id) {
      case ADD_FIELDSET_COMMAND: {
        this.addFieldSet(this.cmpInstance.componentId);
        return;
      }
      case ENABLE_TAB_INDEX_MENU: {
        this.changeTabIndexInFormComponent(true);
        return;
      }
      case CLOSE_TAB_INDEX_MENU: {
        this.changeTabIndexInFormComponent(false);
        return;
      }
    }

    this.notifyService.warning('暂不支持');
  }

  /**
   * 过滤【添加控件】菜单
   * @param formId 组件id
   * @param menuConfig 菜单项
   */
  private assembleAddChildControlMenu(formId: string, menuConfig: ControlContextMenuItem[], viewModelId: string) {
    const formElement = this.domService.domDgMap.get(formId);
    const addChildMenu = menuConfig.find(menu => menu.id === ADD_CHILD_CONTENT_COMMAND);
    if (!addChildMenu) {
      return menuConfig;
    }

    // 根组件下的Form控件，不支持菜单（在一些旧表单中有使用Form作为过滤条件区域的，这种Form是在根组件中）
    const viewModel = this.domService.getViewModelById(viewModelId);
    if (viewModel && !viewModel.parent) {
      menuConfig = menuConfig.filter(menu => menu.id !== ADD_CHILD_CONTENT_COMMAND);
      return menuConfig;
    }

    // form控件下包含表格（Table），则不允许添加控件
    if (formElement.contents && formElement.contents.find(c => c.type === DgControl.Table.type)) {
      menuConfig = menuConfig.filter(menu => menu.id !== ADD_CHILD_CONTENT_COMMAND);
    }

    // 根据设计器环境过滤菜单
    const formBasicService = this.serviceHost.getService('FormBasicService') as FormBasicService;
    const envType = formBasicService && formBasicService.envType;
    addChildMenu.children = addChildMenu.children.filter(item => !item.supportedEnvType || item.supportedEnvType === envType);

    return menuConfig;

  }

  /**
   * 过滤【添加分组】菜单
   * @param formId 组件id
   * @param menuConfig 菜单项
   */
  private assembleAddFieldSetMenu(formId: string, menuConfig: ControlContextMenuItem[], viewModelId: string) {
    const formElement = this.domService.domDgMap.get(formId);
    const addChildMenu = menuConfig.find(menu => menu.id === ADD_FIELDSET_COMMAND);
    if (!addChildMenu) {
      return menuConfig;
    }

    // 根组件下的Form控件，不支持菜单（在一些旧表单中有使用Form作为过滤条件区域的，这种Form是在根组件中）
    const viewModel = this.domService.getViewModelById(viewModelId);
    if (viewModel && !viewModel.parent) {
      menuConfig = menuConfig.filter(menu => menu.id !== ADD_FIELDSET_COMMAND);
      return menuConfig;
    }

    // form控件下包含表格（Table），则不允许添加分组
    if (formElement.contents && formElement.contents.find(c => c.type === DgControl.Table.type)) {
      menuConfig = menuConfig.filter(menu => menu.id !== ADD_FIELDSET_COMMAND);
    }

    return menuConfig;

  }

  /**
   * 添加输入类控件
   * @param menuItem 右键菜单
   * @param componentId form所在组件id
   * @param controlParentElement 输入类控件的父级节点DOM
   */
  addChildControl(menuItem: ControlContextMenuItem, componentId: string, controlParentElement: any) {

    const editorComponentFactory = this.componentFactoryResolver.resolveComponentFactory(BindingEditorComponent);
    const editorComponentFactoryRef = editorComponentFactory.create(this.injector);
    editorComponentFactoryRef.instance.editorParams = {
      viewModelId: this.cmpInstance.viewModelId
    };
    editorComponentFactoryRef.instance.unusedOnly = true;
    editorComponentFactoryRef.instance.bindingControlType = menuItem.id;

    const fieldSelectorDialog = this.modalService.show(editorComponentFactoryRef, {
      title: '绑定',
      width: 900,
      height: 500,
      showButtons: true,
      buttons: editorComponentFactoryRef.instance.modalFooter
    });

    editorComponentFactoryRef.instance.closeModal.subscribe(() => {
      fieldSelectorDialog.close();
    });

    editorComponentFactoryRef.instance.submitModal.subscribe(data => {
      fieldSelectorDialog.close();
      if (!data || !data.value || !data.parameters) {
        return;
      }
      const creationContext = new ControlCreationContextByContextMenu();
      Object.assign(creationContext, {
        componentId,
        controlType: menuItem.id,
        controlParentElement,
        bindingValue: data.value,
        bindingField: data.parameters && data.parameters.selectedData
      });
      this.createControlByContextMenu(creationContext);
    });
  }

  private createControlByContextMenu(creationContext: ControlCreationContextByContextMenu) {
    const formComponent = this.domService.getComponentById(creationContext.componentId);

    if (creationContext.bindingValue.type === 'Form') {
      const bindingEntityField = creationContext.bindingField as DesignViewModelField;

      const controlElement = this.controlCreatorService.createControlBySchemaFeild(bindingEntityField, formComponent.componentType, creationContext.controlType, creationContext.componentId);
      if (!controlElement) {
        return;
      }

      creationContext.controlParentElement.contents.push(controlElement);

      const dgViewModel = this.dgVMService.getDgViewModel(formComponent.viewModel);

      // 添加到分组控件下，需要修改groupId和groupName
      if (creationContext.controlParentElement.type === DgControl.FieldSet.type) {
        dgViewModel.changeField(bindingEntityField.id,
          {
            groupId: creationContext.controlParentElement.id,
            groupName: creationContext.controlParentElement.title
          });
      }

      // 创建的控件类型不是字段默认的编辑器类型
      if (creationContext.controlType !== bindingEntityField.editor.$type) {
        dgViewModel.changeField(bindingEntityField.id,
          {
            editor: {
              $type: creationContext.controlType
            }
          });
      }



    } else {
      const bindingVariableField = creationContext.bindingField as FormVariable;
      // tslint:disable-next-line:max-line-length
      const controlElement = this.controlCreatorService.createControlByVariable(bindingVariableField, formComponent.componentType, creationContext.controlType, creationContext.componentId);
      // 配置状态机。变量没有只读属性，所以控件不是只读的
      controlElement.readonly = 'viewModel.stateMachine && !viewModel.stateMachine[\'editable\']';

      // 配置样式
      controlElement.appearance.class = this.domService.getControlClassByFormUnifiedLayout(controlElement.appearance.class, creationContext.componentId);


      creationContext.controlParentElement.contents.push(controlElement);

      // 添加到分组控件下，需要修改groupId和groupName
      if (creationContext.controlParentElement.type === DgControl.FieldSet.type) {
        const viewModelField = this.domService.getViewModelFieldById(formComponent.viewModel, bindingVariableField.id);
        viewModelField.groupId = creationContext.controlParentElement.id;
        viewModelField.groupName = creationContext.controlParentElement.title;

      }

    }

    this.notifyService.success('添加成功');
    // 刷新form
    this.refreshFormService.refreshFormDesigner.next(this.cmpInstance.id);

  }

  /**
   * 添加分组控件，并选择分组控件中的字段
   * @param componentId 当前form所属组件ID
   */
  addFieldSet(componentId: string) {
    const compFactory = this.componentFactoryResolver.resolveComponentFactory(CreateFieldSetComponent);
    const compRef = compFactory.create(this.injector);

    const modalConfig = {
      title: '添加分组',
      width: 900,
      height: 600,
      showButtons: true,
      buttons: compRef.instance.modalFooter
    };

    const designerHost = this.cmpInstance.options.designerHost;
    compRef.instance.schemaDOMMapping = designerHost.getService('SchemaDOMMapping');
    compRef.instance.componentId = componentId;

    const modalPanel = this.modalService.show(compRef, modalConfig);
    compRef.instance.closeModal.subscribe(() => {
      modalPanel.close();
    });

    compRef.instance.submitModal.subscribe(() => {
      this.refreshFormService.refreshFormDesigner.next();

      modalPanel.close();
    });
  }
  /**
   * 组装卡片组件启用tab索引的菜单
   */
  private assembleEnableTabIndexMenu(menuConfig: ControlContextMenuItem[]): ControlContextMenuItem[] {
    if (!this.checkCanTabIndex()) {
      menuConfig = menuConfig.filter(menu => menu.id !== ENABLE_TAB_INDEX_MENU);
    }
    return menuConfig;
  }

  /**
   * 组装卡片组件关闭tab索引的菜单
   */
  private assembleCloseTabIndexMenu(menuConfig: ControlContextMenuItem[]): ControlContextMenuItem[] {
    if (!this.checkCanTabIndex()) {
      menuConfig = menuConfig.filter(menu => menu.id !== CLOSE_TAB_INDEX_MENU);
    }
    return menuConfig;
  }
  /**
   * 组装卡片组件启用、关闭tab索引的菜单
   */
  private checkCanTabIndex(): boolean {
    const formNode = this.cmpInstance.component;
    const viewModelId = this.cmpInstance.viewModelId;

    // 1、根组件下的Form控件，不支持菜单（在一些旧表单中有使用Form作为过滤条件区域的，这种Form是在根组件中）
    const viewModel = this.domService.getViewModelById(viewModelId);
    if (viewModel && !viewModel.parent) {
      return;
    }
    // 2、组件内不能有table控件
    const table = this.domService.selectNode(formNode, item => item.type === DgControl.Table.type);
    if (table) {
      return;
    }
    // 3、组件内有子级控件
    if (!formNode.contents || !formNode.contents.length) {
      return;
    }
    return true;
  }

  /**
   * Form类组件中启用tab索引
   */
  private changeTabIndexInFormComponent(enable: boolean) {
    this.enableTabIndexInForm(this.cmpInstance.component.contents, enable);

    const msg = enable ? '启用' : '关闭';
    this.notifyService.success(`${msg}成功！`);
    this.refreshFormService.refreshFormDesigner.next();
  }

  private enableTabIndexInForm(contents: any[], enable: boolean) {
    const notAllowedControls = [DgControl.Avatar.type, DgControl.Image.type, DgControl.Tags.type, DgControl.FieldSet.type];

    contents.forEach(control => {
      if (!notAllowedControls.includes(control.type)) {
        control.tabindex = enable ? 1 : -1;
      }

      if (control.contents && control.contents.length) {
        this.enableTabIndexInForm(control.contents, enable);
      }
    });
  }
}

